﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using TlvLib.PacketParsers;
using TlvLib.Packets;

namespace TlvLib
{
    public class NewPacketEventArgs : EventArgs
    {
        public object Packet { get; set; }
        public bool Handled { get; set; }
        public NewPacketEventArgs(object packet)
        {
            Packet = packet;
        }
    }


    public delegate void NewPacketEventHandler(object sender, NewPacketEventArgs args);

    public class PacketHandler
    {
        private readonly PacketReader _packetReader;
        private readonly List<IPacketParser> _packetParsers = new List<IPacketParser>();
        private readonly PacketParsers.LpiReplyPacker _lpiReplyPacker = new LpiReplyPacker();
        private Action<string> _logger;
        private Dictionary<string, DateTime> _receivedPackets = new Dictionary<string, DateTime>();
        private static NLog.Logger _fileLogger = NLog.LogManager.GetCurrentClassLogger();

        public static Func<string, bool> IsInWhiteLists
        {
            get { return _isInWhiteLists; }
            set { _isInWhiteLists = value; }
        }

        private static readonly NLog.Logger FileLogger = NLog.LogManager.GetCurrentClassLogger();
        private static Func<string, bool> _isInWhiteLists = s => false;

        public event NewPacketEventHandler NewPacketReceived;


        public void RaiseNewPacketReceived(NewPacketEventArgs args)
        {
            NewPacketEventHandler handler = NewPacketReceived;
            if (handler != null) handler(this, args);
        }

        public void SetLogger(Action<string> logger)
        {
            foreach (var packetParser in _packetParsers)
            {
                packetParser.Logger = logger;
            }

            _logger = logger;
        }

        public PacketHandler(PacketReader packetReader)
        {
            if (packetReader == null) throw new ArgumentNullException("packetReader");
            _packetReader = packetReader;
            _packetReader.RawPacketReceived += PacketReaderRawPacketReceived;
            InitParsers();
        }

        private void InitParsers()
        {
            _packetParsers.Add(new PacketParser());
            _packetParsers.Add(new CameraStatusReportPacketParser());
        }




        void PacketReaderRawPacketReceived(object sender, RawPacketReceivedEventArgs args)
        {
            var processed = false;
            foreach (var packetParser in _packetParsers)
            {
                if (packetParser.CanParse(args.Packet))
                {
                    processed = true;
                    object obj = null;
                    try
                    {
                        obj = packetParser.Parse(args.Packet);
                    }
                    catch (Exception ex)
                    {
                        _fileLogger.ErrorException("解析数据包出现错误", ex);
                        _logger("解析数据包出现异常，请查看log文件");
                        continue;
                    }

                    var lpi = obj as Packets.LicensePlateInfo;
                    if (lpi != null)
                    {
                        var arg = new NewPacketEventArgs(obj);
                        RaiseNewPacketReceived(arg);
                        if (arg.Handled)
                        {
                            HandleAck(obj);
                        }
                    }

                }

            }

            if (!processed)
            {
                Log("该数据包被丢弃");
            }
        }



        private void HandleAck(object obj)
        {
            if (obj is Packets.LicensePlateInfo)
            {
                var lpi = (Packets.LicensePlateInfo)obj;
                var reply = _lpiReplyPacker.Pack(lpi.PacketId);
                var p = new RawPacket()
                            {
                                IsRequest = false,
                                MessageId = PacketType.LicensePlateInfoAck,
                                Payload = reply
                            };
                _packetReader.Send(p);
            }
        }

        private void Log(string msg)
        {
            if (_logger != null)
            {
                _logger(msg);
            }
        }
    }
}
